package com.yunshipei.core.ui;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.yunshipei.core.R;
import com.yunshipei.core.common.ContentValues;
import com.yunshipei.core.common.DeveloperAppHandler;
import com.yunshipei.core.common.MatchingException;
import com.yunshipei.core.common.XCloudException;
import com.yunshipei.core.download.TabDownloadListener;
import com.yunshipei.core.manager.AdapterPkgHandler;
import com.yunshipei.core.manager.UWAPkgHandler;
import com.yunshipei.core.manager.XCloud2Map;
import com.yunshipei.core.manager.XCloudSDKManager;
import com.yunshipei.core.model.AutoLoginModel;
import com.yunshipei.core.model.CookieModel;
import com.yunshipei.core.model.DeveloperAppModel;
import com.yunshipei.core.model.JavascriptInterfaceModel;
import com.yunshipei.core.model.MatcherResult;
import com.yunshipei.core.model.NativeEventModel;
import com.yunshipei.core.model.RegexModel;
import com.yunshipei.core.model.RequestHeaderSSOModel;
import com.yunshipei.core.model.XCloudAppModel;
import com.yunshipei.core.model.XCloudJsModel;
import com.yunshipei.core.model.XDownloadModel;
import com.yunshipei.core.ui.client.AdapterEnterWebViewClient;
import com.yunshipei.core.ui.client.EnterWebChromeClient;
import com.yunshipei.core.ui.client.EnterWebViewClient;
import com.yunshipei.core.ui.client.FaceWebChromeClient;
import com.yunshipei.core.ui.client.FaceWebViewClient;
import com.yunshipei.core.ui.client.PCModeEnterWebViewClient;
import com.yunshipei.core.ui.view.EnterWebView;
import com.yunshipei.core.ui.view.FaceWebView;
import com.yunshipei.core.utils.CommonUtils;
import com.yunshipei.core.utils.FileUtils;
import com.yunshipei.core.utils.SystemUtils;
import com.yunshipei.core.utils.ViewUtils;
import com.yunshipei.core.utils.YspLogUtils;

import org.chromiun.net.GURLUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.reactivestreams.Publisher;
import org.xwalk.core.XWalkCookieManager;
import org.xwalk.core.XWalkHttpAuthHandler;
import org.xwalk.core.XWalkSettings;
import org.xwalk.core.XWalkView;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

import static org.chromiun.net.ProxyChangeListener.PROXY_YSP_ACTION;

public final class TabItem implements View.OnClickListener, JavascriptInterfaceModel.OnJavascriptInterfaceModelInteractionListener, EnterWebChromeClient.OnEnterWebChromeClientInteractionListener, EnterWebViewClient.OnEnterWebViewClientInteractionListener, FaceWebChromeClient.FaceWebChromeClientInteractionListener {

    private static final String YSP_PROTOCOL = "enterplorer://";
    private static final String UNIVERSAL_WEB_APP = "enterplorer://universal.web.app/";

    public static final String YSP_REFRESH_MODEL_ALL = "all";
    private static final String YSP_REFRESH_MODEL_FACE = "face";
    private static final String YSP_REFRESH_MODEL_BACK = "back";

    private Context mContext;
    private String mUrl = "";
    private String mParentWebViewScope = "";
    private boolean isPageLoadFailed = false;
    private JavascriptInterfaceModel mJavascriptInterfaceModel;
    private int mTextZoom = 100;

    private OnTabItemInteractionListener mTabItemInteractionListener;

    private View mContentView;
    private View mAdapterLoading;
    private View mPageLoadFailed;
    private TextView mLoadingMsg;
    private ImageView mLoadingImage;
    private FrameLayout mWebViewPlaceHolder;
    private TextView tvErrorMsg;
    private TextView tvCloseCurrentPage;
    private TextView tvReloadPage;
    private TextView tvOpenPCPage;
    private RelativeLayout mPageLoadErrorMsgContainer;

    private EnterWebView mWebView;
    private FaceWebView mFaceView;

    private String mBackWebViewOriginUrl = "";
    private String mFaceWebViewOriginUrl = "";

    private AdapterEnterWebViewClient mAdapterEnterWebViewClient;
    private PCModeEnterWebViewClient mPcModeEnterWebViewClient;
    private EnterWebChromeClient mAdapterWebChromeClient;
    private EnterWebChromeClient mPCModeWebChromeClient;

    private MatcherResult mMatcherResult;
    private CompositeDisposable mDisposables = new CompositeDisposable();

    //任何一个链接进来，
    TabItem(Context context, String url, int textZoom, OnTabItemInteractionListener tabItemInteractionListener) {
        this.mContext = context;
        this.mUrl = url;
        Log.e("mUrl",mUrl);
        this.mTextZoom = textZoom;
        this.mTabItemInteractionListener = tabItemInteractionListener;

    }

    @SuppressLint("SetJavaScriptEnabled")
    void loadView() {
        mContentView = View.inflate(mContext, R.layout.tab_item_content, null);
        mAdapterLoading = mContentView.findViewById(R.id.fl_adapter_loading);
        mPageLoadFailed = mContentView.findViewById(R.id.rl_web_view_load_failure_refresh);
        mLoadingMsg = (TextView) mContentView.findViewById(R.id.waiting_tv);
        mLoadingImage = (ImageView) mContentView.findViewById(R.id.iv_loading);
        mAdapterLoading.setOnClickListener(null);
        mPageLoadFailed.setOnClickListener(this);
        mAdapterLoading.setVisibility(View.INVISIBLE);
        mPageLoadFailed.setVisibility(View.INVISIBLE);
        mWebViewPlaceHolder = (FrameLayout) mContentView.findViewById(R.id.fl_web_view_place_holder);
        mPageLoadErrorMsgContainer = (RelativeLayout) mContentView.findViewById(R.id.rv_page_load_error_container);
        mPageLoadErrorMsgContainer.setVisibility(View.INVISIBLE);
        tvErrorMsg = (TextView) mContentView.findViewById(R.id.tv_error_msg);
        tvReloadPage = (TextView) mContentView.findViewById(R.id.tv_reload_tab_item);
        tvCloseCurrentPage = (TextView) mContentView.findViewById(R.id.tv_close_tab_item);
        tvOpenPCPage = (TextView) mContentView.findViewById(R.id.tv_open_pc_page);
        tvReloadPage.setOnClickListener(this);
        tvCloseCurrentPage.setOnClickListener(this);
        tvOpenPCPage.setOnClickListener(this);
        mWebView = new EnterWebView(mContext);
        TabDownloadListener tabDownloadListener = new TabDownloadListener(mContext, new TabDownloadListener.XWalkDownloadListenerCallback() {
            @Override
            public void yspDownload(String fromUrl, XDownloadModel xDownloadModel) {
                mTabItemInteractionListener.yspDownload(TabItem.this, fromUrl, xDownloadModel);
            }
        });
        mWebView.setYspDownloadListener(tabDownloadListener);

        ArrayList<RequestHeaderSSOModel> requestHeaderSSOModels = mTabItemInteractionListener.getRequestHeaderSSOModels();
        if (requestHeaderSSOModels != null && requestHeaderSSOModels.size() > 0) {
            JSONObject jsonObject = new JSONObject();
            for (RequestHeaderSSOModel requestHeaderSSOModel : requestHeaderSSOModels) {
                try {
                    HashMap<String, String> hashMap = requestHeaderSSOModel.getAddHeaders();
                    JSONObject innerObject = new JSONObject();
                    for (Map.Entry<String, String> entry : hashMap.entrySet()) {
                        String key = entry.getKey();
                        String value = entry.getValue();
                        innerObject.put(key, value);
                    }
                    String host = requestHeaderSSOModel.getHost();
                    host = host.replaceAll("\\.", "-");
                    jsonObject.put(host, innerObject);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            GURLUtils.setHeader(jsonObject.toString());
        }
        XWalkSettings settings = mWebView.getSettings();
        settings.setTextZoom(mTextZoom);
        settings.setUseWideViewPort(true);
        settings.setLoadWithOverviewMode(true);
        settings.setSupportZoom(true);

        if (mUrl.startsWith(UNIVERSAL_WEB_APP)) {
            loadUniversalWebApp(mUrl);
        } else if (mUrl.contains(ContentValues.YSP_PARAM_FORCE_PC)) {
            String loadUrl = getLoadUrl(mUrl);
            loadNoMatch(loadUrl);
        } else {
            loadCustomerAdapter();
        }
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.rl_web_view_load_failure_refresh) {
            mPageLoadFailed.setVisibility(View.INVISIBLE);
            isPageLoadFailed = false;
            refresh();
        } else if (id == R.id.tv_reload_tab_item) {
            mPageLoadErrorMsgContainer.setVisibility(View.INVISIBLE);
            loadCustomerAdapter();
        } else if (id == R.id.tv_close_tab_item) {
            mPageLoadErrorMsgContainer.setVisibility(View.INVISIBLE);
            closeWindow();
        } else if (id == R.id.tv_open_pc_page) {
            mPageLoadErrorMsgContainer.setVisibility(View.INVISIBLE);
            String loadUrl = getLoadUrl(mUrl);
            loadNoMatch(loadUrl);
        }
    }

    private void loadUniversalWebApp(String url) {
        showLoading("正在下载小程序");
        new UWAPkgHandler(mContext).start(url).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
            @Override
            public void accept(String url) throws Exception {
                hideLoading();
                loadNoMatch(url);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                hideLoading();
                Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    //加载适配应用,区分是否是扫码加载出来的，以及各种正则匹配
    private void loadCustomerAdapter() {
        //是否需要从网络加载适配包和运行时
        XCloud2Map xCloud2Map = XCloud2Map.getInstance();
        final boolean flag = xCloud2Map.shouldLoadAdapterFromNet();  //服务器是否支持动态下载适配包和运行时
        showLoading("正在配置应用，请稍候");
        //下载适配包，运行时，解析，加载
        Disposable disposable = matching(mUrl).flatMap(new Function<MatcherResult, Publisher<MatcherResult>>() {
            @Override
            public Publisher<MatcherResult> apply(final MatcherResult matcherResult) throws Exception {
                final DeveloperAppModel developerAppModel = mTabItemInteractionListener.getDeveloperAppModel();
                if (developerAppModel != null) {
                    return new AdapterPkgHandler(mContext, matcherResult.getCloudAppModle()).starOnlyRuntime().flatMap(new Function<XCloudAppModel, Publisher<MatcherResult>>() {
                        @Override
                        public Publisher<MatcherResult> apply(XCloudAppModel xCloudAppModel) throws Exception {
                            matcherResult.setDeveloperAppModel(developerAppModel);
                            return Flowable.just(matcherResult);
                        }
                    });
                }
                if (flag) {
                    //需要手动加载适配包和运行时
                    return new AdapterPkgHandler(mContext, matcherResult.getCloudAppModle()).start().map(new Function<XCloudAppModel, MatcherResult>() {
                        @Override
                        public MatcherResult apply(XCloudAppModel xCloudAppModel) throws Exception {
                            return matcherResult;
                        }
                    });
                } else {
                    //使用登录时已有的运行时和适配包
                    return Flowable.just(matcherResult);
                }
            }
        }).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<MatcherResult>() {
            @Override
            public void accept(MatcherResult matcherResult) throws Exception {
                hideLoading();
                String adapter = matcherResult.getAdapter();
                if (TextUtils.isEmpty(adapter)) {
                    loadWithMatch();
                } else {
                    loadAdapter(matcherResult);
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                hideLoading();
                if (throwable instanceof MatchingException) {
                    //没有匹配到的异常，直接加载pc版
                    loadWithMatch();
                } else {
                    String errorMsg = XCloudSDKManager.getInstance().generateError(throwable);
                    if (!TextUtils.isEmpty(errorMsg)) {
                        String tempMsg = CommonUtils.replaceBlank(errorMsg).toLowerCase();
                        if (tempMsg.contains("timedout") || tempMsg.contains("timeout")) {
                            errorMsg = "请求超时...";
                        }
                    }
                    showPageLoadErrorInfo(errorMsg);
                }
            }
        });
        mDisposables.add(disposable);
    }

    private void showPageLoadErrorInfo(String errorMsg) {
        hideLoading();
        tvErrorMsg.setText(errorMsg);
        mPageLoadErrorMsgContainer.setVisibility(View.VISIBLE);
        tvOpenPCPage.setVisibility(mUrl.startsWith(YSP_PROTOCOL) ? View.GONE : View.VISIBLE);
    }

    //创建一个纯PC的WebView，这里面的WebView不会再shouldOverrideURLLoading方法中去匹配正则
    private void loadNoMatch(String url) {

        boolean isDebug = mTabItemInteractionListener.isDebugMode();
        mJavascriptInterfaceModel = new JavascriptInterfaceModel(url, mWebView, null, isDebug, this);
        mWebView.addJavascriptInterface(mJavascriptInterfaceModel, ContentValues.JS_OBJECT_CROSSWALK);
        initXWalkViewJavascriptInterface(mWebView);
        mPcModeEnterWebViewClient = new PCModeEnterWebViewClient(mWebView, this);
        mWebView.setWebViewClient(mPcModeEnterWebViewClient);
        mPCModeWebChromeClient = new EnterWebChromeClient(mWebView, this);
        mWebView.setWebChromeClient(mPCModeWebChromeClient);
        attachCookie();
        sendProxyReceiver();
        mWebView.getSettings().setLayoutAlgorithm(XWalkSettings.LayoutAlgorithm.NARROW_COLUMNS);
        mWebView.getSettings().setUseWideViewPort(true);
        mWebView.getSettings().setJavaScriptEnabled(true);
        //自适应屏幕
        mWebView.getSettings().setUseWideViewPort(true);
        mWebView.getSettings().setLoadWithOverviewMode(true);
        //自动缩放
        mWebView.getSettings().setBuiltInZoomControls(true);
        mWebView.getSettings().setSupportZoom(true);
        //支持获取手势焦点
        mWebView.requestFocusFromTouch();


        mWebView.loadUrl(url);
        mWebViewPlaceHolder.addView(mWebView);
    }

    //创建适配的WebView，一定是适配的
    @SuppressLint("AddJavascriptInterface")
    private void loadAdapter(@NonNull MatcherResult matcherResult) {
     //   mWebView.setVisibility(View.VISIBLE);

        String loadUrl = getLoadUrl(mUrl);
        //设置为全局运行时
        String globalRT = mTabItemInteractionListener.getGlobalRTVersion();
        if (!TextUtils.isEmpty(globalRT)) {
            matcherResult.getCloudAppModle().setRuntimeVersion(globalRT);
        }
        mMatcherResult = matcherResult;
        //设置功能配置
        boolean isDebug = mTabItemInteractionListener.isDebugMode();
        mJavascriptInterfaceModel = new JavascriptInterfaceModel(loadUrl, mWebView, mMatcherResult, isDebug, this);
        mWebView.addJavascriptInterface(mJavascriptInterfaceModel, ContentValues.JS_OBJECT_CROSSWALK);
        initXWalkViewJavascriptInterface(mWebView);
        //设置适配
        mAdapterEnterWebViewClient = new AdapterEnterWebViewClient(mWebView, mUrl, matcherResult, this);
        mWebView.setWebViewClient(mAdapterEnterWebViewClient);
        mAdapterWebChromeClient = new EnterWebChromeClient(mWebView, this);
        mWebView.setWebChromeClient(mAdapterWebChromeClient);
        Uri uri = Uri.parse(mUrl);
        if (uri != null) {
            String configUA = matcherResult.getCloudAppModle().getUserAgent();
            String defaultUA = ContentValues.ENTERPLORER_USER_AGENT + getAppVersion();
            YspLogUtils.d("manifest UA:" + configUA + "     default UA:" + defaultUA);
            String ua = TextUtils.isEmpty(configUA) ? defaultUA : configUA;
            mWebView.setUserAgentString(ua);
            boolean isSupport2WebView = isSupport2WebView(matcherResult);
            //伪装适配的url
            String schema = uri.getScheme();
            String host = uri.getHost();
            int port = uri.getPort();
            String params = "?ua=Enterplorer-" + getAppVersion() + ",Android-" + Build.VERSION.RELEASE +
                    "&isDebug=" + (isDebug ? "1" : "0") +
                    "&is2WebView=" + (isSupport2WebView ? "1" : "0") +
                    "&modelURL=xcloud2json/" + matcherResult.getAdapter().replace("adapter://", "") +
                    "&targetURL=" + Uri.encode(CommonUtils.removeParams(loadUrl, new String[]{ContentValues.WEB_APP_ID, ContentValues.WEB_APP_NAME})) +
                    "&hasAutoLogin=" + mJavascriptInterfaceModel.isEnableAutoLogin(mUrl);
            String runtimeVersion = matcherResult.getCloudAppModle().getRuntimeVersion();
            if (!TextUtils.isEmpty(runtimeVersion) && runtimeVersion.startsWith("^")) {
                runtimeVersion = runtimeVersion.replace("^", "").split("\\.")[0] + ".+";
            }
            String runtimePath = schema + "://" + host + (port == -1 ? "" : ":" + port) + File.separator + ContentValues.APP_ENGINE_ROOT_PATH + File.separator + runtimeVersion;
            if (isSupport2WebView) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    WebView.setWebContentsDebuggingEnabled(true);
                }
                mJavascriptInterfaceModel.setSupport2WebView(true);
                //加载后面WebView的内容
                mBackWebViewOriginUrl = runtimePath + File.separator + "runtimeEngineWithApp.html" + params;
                attachCookie();
                mWebView.loadUrl(mBackWebViewOriginUrl);
                //加载前面WebView的内容
                mFaceView = new FaceWebView(mContext);
                mFaceView.getSettings().setTextZoom(mTextZoom);
                mJavascriptInterfaceModel.setFaceWebView(mFaceView);
                mFaceView.addJavascriptInterface(mJavascriptInterfaceModel, ContentValues.JS_OBJECT_CROSSWALK);
                initWebViewJavascriptInterface(mFaceView);
                mFaceView.setWebViewClient(new FaceWebViewClient(matcherResult));
                mFaceView.setFaceWebChromeClient(new FaceWebChromeClient(this));
                mFaceWebViewOriginUrl = runtimePath + File.separator + "app.html" + params;
                mFaceView.loadUrl(mFaceWebViewOriginUrl);
                mWebViewPlaceHolder.addView(mFaceView);
            } else {
                //单WebView，只使用后面的WebView加载内容
                mBackWebViewOriginUrl = runtimePath + File.separator + "app.html" + params;
                attachCookie();
                sendProxyReceiver();
                mWebView.loadUrl(mBackWebViewOriginUrl);
                mWebViewPlaceHolder.addView(mWebView);
            }
        } else {
            sendProxyReceiver();
            mWebView.loadUrl(loadUrl);
            mWebViewPlaceHolder.addView(mWebView);
        }
    }

    private boolean isSupport2WebView(MatcherResult matcherResult) {
        boolean runtimeSupport2WebView = false;
        String runtimeVersion = matcherResult.getCloudAppModle().getRuntimeVersion();
        if (!TextUtils.isEmpty(runtimeVersion)) {
            runtimeVersion = runtimeVersion.startsWith("^") ? (runtimeVersion.replace("^", "").split("\\.")[0] + ".+") : runtimeVersion;
            File runtimePacFile = new File(mContext.getFilesDir().getPath() + File.separator + ContentValues.APP_ENGINE_ROOT_PATH + File.separator + runtimeVersion, "package.json");
            if (runtimePacFile.exists()) {
                String content = FileUtils.readFile(runtimePacFile.getAbsolutePath());
                try {
                    JSONObject pacJSONObject = new JSONObject(content);
                    String mode = pacJSONObject.optString("mode", "");
                    if (!TextUtils.isEmpty(mode) && "2webview".equals(mode)) {
                        runtimeSupport2WebView = true;
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && runtimeSupport2WebView && matcherResult.getCloudAppModle().isAdapterSupport2WebView() && mTabItemInteractionListener.isOpen2WebView();
    }

    @Override
    public String getAppVersion() {
        String pkgName = mContext.getPackageName();
        if (!TextUtils.isEmpty(pkgName) && pkgName.startsWith("com.yunshipei.enterplorer")) {
            return SystemUtils.getVersionName(mContext);
        } else {
            return "4.0.0";
        }
    }

    //创建常规的WebView，这类WebView的特点和纯PC的WebView不同之处在于，他的shouldOverrideURLLoading方法中会去匹配每个url
    private void loadWithMatch() {
        Log.e("mUrls",mUrl);
        //设置功能配置
        boolean isDebug = mTabItemInteractionListener.isDebugMode();
        mJavascriptInterfaceModel = new JavascriptInterfaceModel(mUrl, mWebView, null, isDebug, this);
        mWebView.addJavascriptInterface(mJavascriptInterfaceModel, ContentValues.JS_OBJECT_CROSSWALK);
        initXWalkViewJavascriptInterface(mWebView);
        //设置适配
        mAdapterEnterWebViewClient = new AdapterEnterWebViewClient(mWebView, mUrl, null, this);
        DeveloperAppModel developerAppModel = mTabItemInteractionListener.getDeveloperAppModel();
        if (developerAppModel != null) {
            mAdapterEnterWebViewClient.setDeveloperAppModel(developerAppModel);
        }
        mWebView.setWebViewClient(mAdapterEnterWebViewClient);
        mAdapterWebChromeClient = new EnterWebChromeClient(mWebView, this);
        mWebView.setWebChromeClient(mAdapterWebChromeClient);
        String url = mUrl;
        if (isAdapterApp(url)) {
            url = CommonUtils.removeParams(url, new String[]{ContentValues.WEB_APP_ID, ContentValues.WEB_APP_NAME});
        }
        attachCookie();
        sendProxyReceiver();
        mWebView.loadUrl(isAdapterApp(url) ? url : getLoadUrl(url));
        mWebViewPlaceHolder.addView(mWebView);

    }

    private void sendProxyReceiver() {
        Intent intent = new Intent(PROXY_YSP_ACTION);
        mContext.sendBroadcast(intent);
    }

    private void initXWalkViewJavascriptInterface(EnterWebView webView) {
        List<XCloudJsModel> xCloudJsModels = mTabItemInteractionListener.getXCloudJsModels();
        for (XCloudJsModel xCloudJsModel : xCloudJsModels) {
            webView.addJavascriptInterface(xCloudJsModel.getObject(), xCloudJsModel.getObjName());
        }
    }

    /**
     * 判断当前实际WebView加载的url是否是单点登录的，单点登录的形式是url中加token参数的形式
     */
    private String getLoadUrl(String url) {
        Uri uri = Uri.parse(url);
        if (uri != null) {
            String host = uri.getHost();
            if (mTabItemInteractionListener != null) {
                String token = mTabItemInteractionListener.getUrlToken(host);
                if (!TextUtils.isEmpty(token)) {
                    Set<String> set = uri.getQueryParameterNames();
                    if (set != null && set.size() > 0) {
                        url += ("&" + token);
                    } else {
                        url += ("?" + token);
                    }
                }
            }
        }
        return url;
    }

    @SuppressLint({"AddJavascriptInterface", "JavascriptInterface"})
    private void initWebViewJavascriptInterface(WebView webView) {
        List<XCloudJsModel> xCloudJsModels = mTabItemInteractionListener.getXCloudJsModels();
        for (XCloudJsModel xCloudJsModel : xCloudJsModels) {
            webView.addJavascriptInterface(xCloudJsModel.getObject(), xCloudJsModel.getObjName());
        }
    }

    /**
     * 匹配进来的url，匹配有三处需要做：
     * 1、打开一个tabItem的时候需要匹配
     * 2、适配调用yspUser的openWindow方法的时候
     * 3、webview的shouldOVerrideUrlLoading方法中，如果不是适配的webview，则需要匹配
     * <p>
     *
     * @param appUrl 需要匹配的url
     */
    private Flowable<MatcherResult> matching(final String appUrl) {
        DeveloperAppModel developerAppModel = mTabItemInteractionListener.getDeveloperAppModel();
        if (developerAppModel != null) {
            final String url = developerAppModel.getUrl();
            return new DeveloperAppHandler(developerAppModel).start().flatMap(new Function<XCloudAppModel, Publisher<MatcherResult>>() {
                @Override
                public Publisher<MatcherResult> apply(XCloudAppModel xCloudAppModel) throws Exception {
                    if (isAdapterApp(url)) {
                        return Flowable.just(new MatcherResult(xCloudAppModel));
                    } else {
                        YspLogUtils.matchStart(url);
                        List<RegexModel> regexModels = xCloudAppModel.getRegexModelList();
                        for (RegexModel regexModel : regexModels) {
                            List<String> matcherList = regexModel.getMatcherList();
                            for (String matcher : matcherList) {
                                try {
                                    if (url.matches(matcher)) {
                                        MatcherResult matcherResult = new MatcherResult(regexModel.getTargetURl(), xCloudAppModel);
                                        YspLogUtils.matchEnd(url);
                                        return Flowable.just(matcherResult);
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        YspLogUtils.matchEnd(url);
                        return Flowable.error(new MatchingException("匹配失败"));
                    }
                }
            });
        } else {
            if (isAdapterApp(appUrl)) {
                String scope = CommonUtils.getHost(appUrl);
                if (!TextUtils.isEmpty(scope)) {
                    List<XCloudAppModel> xCloudAppModels = XCloud2Map.getInstance().getXCloudAppModels();
                    for (XCloudAppModel xCloudAppModel : xCloudAppModels) {
                        String xScope = xCloudAppModel.getScope();
                        if (xScope.equals(scope)) {
                            return Flowable.just(new MatcherResult(xCloudAppModel));
                        }
                    }
                } else {
                    return Flowable.error(new XCloudException("enterplorer协议scope为空"));
                }
                boolean flag = XCloud2Map.getInstance().shouldLoadAdapterFromNet();
                String errorMsg = flag ? "接口未返回当前应用的manifest" : "适配包不存在";
                return Flowable.error(new XCloudException(errorMsg));
            }
            //其他协议
            return Flowable.just(appUrl).flatMap(new Function<String, Publisher<MatcherResult>>() {
                @Override
                public Publisher<MatcherResult> apply(String url) throws Exception {
                    url = CommonUtils.removeParams(url, new String[]{ContentValues.WEB_APP_ID, ContentValues.WEB_APP_NAME});
                    YspLogUtils.matchStart(url);
                    //优先匹配当前适配页面的资源
                    if (mMatcherResult != null) {
                        XCloudAppModel xCloudAppModel = mMatcherResult.getCloudAppModle();
                        if (xCloudAppModel != null) {
                            List<RegexModel> regexModels = xCloudAppModel.getRegexModelList();
                            for (RegexModel regexModel : regexModels) {
                                List<String> matcherList = regexModel.getMatcherList();
                                for (String matcher : matcherList) {
                                    try {
                                        if (url.matches(matcher)) {
                                            MatcherResult matcherResult = new MatcherResult(regexModel.getTargetURl(), xCloudAppModel);
                                            YspLogUtils.matchEnd(url);
                                            return Flowable.just(matcherResult);
                                        }
                                    } catch (Exception ignored) {
                                    }
                                }
                            }
                        }
                    }
                    List<XCloudAppModel> xCloudAppModels = XCloud2Map.getInstance().getXCloudAppModels();
                    List<XCloudAppModel> tempModels = new ArrayList<>();
                    tempModels.addAll(xCloudAppModels);
                    //匹配前一个TabIte的scope的适配包
                    if (!TextUtils.isEmpty(mParentWebViewScope)) {
                        for (XCloudAppModel xCloudAppModel : xCloudAppModels) {
                            String scope = xCloudAppModel.getScope();
                            if (!TextUtils.isEmpty(scope) && scope.equals(mParentWebViewScope)) {
                                List<RegexModel> regexModels = xCloudAppModel.getRegexModelList();
                                for (RegexModel regexModel : regexModels) {
                                    List<String> matcherList = regexModel.getMatcherList();
                                    for (String matcher : matcherList) {
                                        try {
                                            if (url.matches(matcher)) {
                                                MatcherResult matcherResult = new MatcherResult(regexModel.getTargetURl(), xCloudAppModel);
                                                YspLogUtils.matchEnd(url);
                                                return Flowable.just(matcherResult);
                                            }
                                        } catch (Exception ignored) {
                                        }
                                    }
                                }
                                tempModels.remove(xCloudAppModel);
                                break;
                            }
                        }
                    }
                    //匹配剩余没有匹配过的
                    for (XCloudAppModel appModule : tempModels) {
                        List<RegexModel> regexModels = appModule.getRegexModelList();
                        for (RegexModel regexModel : regexModels) {
                            List<String> matcherList = regexModel.getMatcherList();
                            for (String matcher : matcherList) {
                                try {
                                    if (url.matches(matcher)) {
                                        MatcherResult matcherResult = new MatcherResult(regexModel.getTargetURl(), appModule);
                                        YspLogUtils.matchEnd(url);
                                        return Flowable.just(matcherResult);
                                    }
                                } catch (Exception ignored) {
                                }
                            }
                        }
                    }
                    YspLogUtils.matchEnd(url);
                    return Flowable.error(new MatchingException("匹配失败"));
                }
            });
        }
    }

    private boolean isAdapterApp(String url) {
        return url.startsWith(YSP_PROTOCOL) && !url.startsWith(UNIVERSAL_WEB_APP);
    }

    private void attachCookie() {
        ArrayList<CookieModel> cookieModels = mTabItemInteractionListener.getCookieModels();
        if (cookieModels != null) {
            XWalkCookieManager cookieManager = new XWalkCookieManager();
            cookieManager.setAcceptCookie(true);
            for (CookieModel cookieModel : cookieModels) {
                String url = cookieModel.getUrl();
                String cookieStr = cookieModel.getCookieStr();
                if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(cookieStr)) {
                    cookieManager.setCookie(url, cookieStr);
                }
            }
        }
    }

    void setParentWebViewScope(String parentWebViewScope) {
        this.mParentWebViewScope = parentWebViewScope;
    }

    void loadWebViewOriginBack() {
        if (!mWebView.backHistory()) {
            //这个WebView已经返回到顶部了
            mTabItemInteractionListener.tabItemBack(this);
        }
    }

    View getTabContentView() {
        return mContentView;
    }

    boolean isAdapter() {
        return mMatcherResult != null;
    }

    /**
     * 调用适配应用的js的返回
     */
    void loadYspJsBack() {
        if (mFaceView != null) {
            mFaceView.loadJsBack(getJSBackCallback());
        } else {
            mWebView.loadJsBack(getJSBackCallback());
        }
    }

    @Override
    public void onBack() {
        mTabItemInteractionListener.tabItemBack(this);
    }

    @Override
    public void showLoading(String message) {
        if (mTabItemInteractionListener == null || !mTabItemInteractionListener.showAdapterLoading(message)) {
            AnimationDrawable animationDrawable = (AnimationDrawable) mLoadingImage.getDrawable();
            mAdapterLoading.setVisibility(View.VISIBLE);
            mLoadingMsg.setText(message);
            if (!animationDrawable.isRunning()) {
                animationDrawable.start();
            }
        }
    }

    @Override
    public void hideLoading() {
        if (mTabItemInteractionListener == null || !mTabItemInteractionListener.hideAdapterLoading()) {
            AnimationDrawable animationDrawable = (AnimationDrawable) mLoadingImage.getDrawable();
            mAdapterLoading.setVisibility(View.INVISIBLE);
            if (animationDrawable.isRunning()) {
                animationDrawable.stop();
            }
        }
    }

    void refresh() {
        if (mMatcherResult != null) {
            adapterRefresh();
        } else {
            originBackWebViewRefresh();
        }
    }
    //============= 刷新 end ============

    void forward() {
        if (mMatcherResult != null) return;
        if (mWebView != null) {
            mWebView.forwardHistory();
        }
    }

    void netChange(boolean netAvailable, boolean isTypeWifi) {
        if (mMatcherResult != null) {
            if (netAvailable) {
                if (mFaceView != null) {
                    mFaceView.loadJsNetConnected(isTypeWifi);
                } else {
                    mWebView.loadJsNetConnected(isTypeWifi);
                }
            } else {
                if (mFaceView != null) {
                    mFaceView.loadJsNetDisConnected();
                } else {
                    mWebView.loadJsNetDisConnected();
                }
            }
        }
    }

    boolean isYspWebApp() {
        return mMatcherResult != null || mUrl.startsWith("enterplorer://");
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    void chooseSystemFile(Intent intent, int requestCode) {
        switch (requestCode) {
            case TabFragment.FILE_CHOOSER_RESULT_CODE:
                mWebView.getWebChromeClient().getValueCallback().onReceiveValue(intent == null ? null : intent.getData());
                break;
            case TabFragment.FACE_WEB_VIEW_FILE_CHOOSER_RESULT_CODE:
                Uri[] results = null;
                if (intent != null) {
                    String dataString = intent.getDataString();
                    ClipData clipData = intent.getClipData();
                    if (clipData != null) {
                        results = new Uri[clipData.getItemCount()];
                        for (int i = 0; i < clipData.getItemCount(); i++) {
                            ClipData.Item item = clipData.getItemAt(i);
                            results[i] = item.getUri();
                        }
                    }
                    if (!TextUtils.isEmpty(dataString)) {
                        results = new Uri[]{Uri.parse(dataString)};
                    }
                }
                mFaceView.getFaceWebChromeClient().getFilePathCallback().onReceiveValue(results);
                break;
        }
    }

    //截取当前页面的截图
    String getSnapshot() {
        if (mPageLoadFailed.getVisibility() == View.VISIBLE) {
            return captureView(mPageLoadFailed);
        }
        if (mPageLoadErrorMsgContainer.getVisibility() == View.VISIBLE) {
            return captureView(mPageLoadErrorMsgContainer);
        }
        if (mMatcherResult != null && mFaceView != null) {
            return captureView(mFaceView);
        }
        return captureXWalkView(mWebView);
    }

    private String captureView(View view) {
        view.buildDrawingCache();
        Bitmap bitmap = view.getDrawingCache();
        if (bitmap != null) {
            try {
                String fileName = mContext.getCacheDir() + File.separator + System.currentTimeMillis() + ".jpg";
                FileOutputStream fos = new FileOutputStream(fileName);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 5, fos);
                fos.close();
                bitmap.recycle();
                view.destroyDrawingCache();
                return fileName;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    private String captureXWalkView(XWalkView xWalkView) {
        TextureView textureView = ViewUtils.findXWalkTextureView(xWalkView);
        if (textureView != null) {
            Bitmap bitmap = textureView.getBitmap();
            if (bitmap != null) {
                try {
                    String fileName = mContext.getCacheDir() + File.separator + System.currentTimeMillis() + ".jpg";
                    FileOutputStream fos = new FileOutputStream(fileName);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 5, fos);
                    fos.close();
                    bitmap.recycle();
                    return fileName;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }

    EnterWebView getEnterWebView() {
        return mWebView;
    }

    String getOriginURL() {
        return mUrl;
    }

    boolean isPageLoadFailed() {
        return isPageLoadFailed;
    }

    //========= 刷新 start ============
    private void adapterRefresh() {
        if (mMatcherResult != null && mFaceView != null) {
            faceWebViewRefresh();
        } else {
            xWalkWebViewRefresh();
        }
    }

    private void xWalkWebViewRefresh() {
        mWebView.loadJsRefresh(new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String value) {
                if (TextUtils.isEmpty(value) || !"true".equals(value)) {
                    originBackWebViewRefresh();
                }
            }
        });
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void faceWebViewRefresh() {
        if (mMatcherResult != null && mFaceView != null) {
            mFaceView.loadJsRefresh(new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    if (TextUtils.isEmpty(value) || !"true".equals(value)) {
                        commandRefresh(YSP_REFRESH_MODEL_ALL);
                    }
                }
            });
        }
    }

    private void commandRefresh(String command) {
        mJavascriptInterfaceModel.setReload(command);
        if (YSP_REFRESH_MODEL_ALL.equals(command)) {
            originBackWebViewRefresh();
            originFaceWebViewRefresh();
        } else if (YSP_REFRESH_MODEL_BACK.equals(command)) {
            originBackWebViewRefresh();
        } else if (YSP_REFRESH_MODEL_FACE.equals(command)) {
            originFaceWebViewRefresh();
        }
    }

    private void originBackWebViewRefresh() {
        mWebView.reload(0);
    }

    private void originFaceWebViewRefresh() {
        if (mMatcherResult != null && mFaceView != null) {
            mFaceView.reload();
        }
    }

    private ValueCallback<String> getJSBackCallback() {
        return new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String value) {
                boolean newBack = false;
                if (mMatcherResult != null) {
                    XCloudAppModel xCloudAppModel = mMatcherResult.getCloudAppModle();
                    String runtimeVersion = xCloudAppModel.getRuntimeVersion();
                    if (runtimeVersion.startsWith("^")) {
                        runtimeVersion = runtimeVersion.replace("^", "");
                    }
                    int index = runtimeVersion.indexOf("-");
                    if (index != -1) {
                        runtimeVersion = runtimeVersion.substring(0, index);
                    }
                    String[] chars = runtimeVersion.split("\\.");
                    String[] srcChars = "2.1.9".split("\\.");
                    if (chars.length == srcChars.length) {
                        for (int i = 0; i < 3; i++) {
                            int ver = Integer.parseInt(chars[i]);
                            int srcVer = Integer.parseInt(srcChars[i]);
                            if (ver == srcVer) continue;
                            newBack = ver > srcVer;
                            break;
                        }
                    }
                }
                if (newBack) {
                    if (TextUtils.isEmpty(value) || !"true".equals(value)) {
                        onBack();
                    }
                }
            }
        };
    }

    @Override
    public void onLoadAdapter() {
        if (mMatcherResult != null && !TextUtils.isEmpty(mMatcherResult.getAdapter())) {
            String target = Uri.encode(mUrl);
            boolean hasAutoLogin = mJavascriptInterfaceModel.isEnableAutoLogin(mUrl);
            if (mFaceView != null) {
                mFaceView.loadAdapter(mMatcherResult.getAdapter(), target, hasAutoLogin);
            } else {
                mWebView.loadAdapter(mMatcherResult.getAdapter(), target, hasAutoLogin);
            }
        }
    }

    @Override
    public void onRefresh(String refreshModel) {
        commandRefresh(refreshModel);
    }

    /**
     * 获取收藏的URL，如果是适配，直接返回targetURL,如果不是适配，返回当前最新加载的URL，
     * 如果是enterplorer协议，则直接返回enterplorer协议的链接
     *
     * @return 收藏URL
     */
    String getWebViewURL() {
        if (mWebView != null && mMatcherResult == null && !mUrl.startsWith("enterplorer://")) {
            return mWebView.getUrl();
        } else {
            return mUrl;
        }
    }

    @Override
    public void closeWindow() {
        mTabItemInteractionListener.onCloseWindow(this);
    }

    @Override
    public void openWindow(final String url) {
        if (url.contains(ContentValues.YSP_PARAM_FORCE_PC) || url.contains(ContentValues.YSP_PARAM_FILE_PREVIEW)) {
            AndroidSchedulers.mainThread().scheduleDirect(new Runnable() {
                @Override
                public void run() {
                    mTabItemInteractionListener.openNewWebViewLoadUrl(url);
                }
            });
        } else {
            //OpenWindow是提供给适配页面的方法，对象为yspUser，如果能匹配上则打开新的窗口加载，如果匹配不上，则交给用户处理是，如果用户不处理，则直接打开pc版的页面
            Disposable disposable = matching(url).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<MatcherResult>() {
                @Override
                public void accept(MatcherResult matcherResult) throws Exception {
                    //如果匹配上了，直接打开新的WebView加载适配
                    mTabItemInteractionListener.openNewWebViewLoadUrl(url);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    //匹配不上，需要通知客户端，客户端可能会更具当前页面定制（中弘需求）
                    if (!mTabItemInteractionListener.shouldHandleNoMatcherUrlFromOpenWindow(url)) {
                        mTabItemInteractionListener.openNewWebViewLoadUrl(url);
                    }
                }
            });
            mDisposables.add(disposable);
        }
    }

    @Override
    public void updateProgress(int progress) {
        //这里加判空处理，在WebView stop的时候有可能出现bug
        if (mTabItemInteractionListener != null) {
            mTabItemInteractionListener.updateProgress(this, progress);
        }
    }

    @Override
    public boolean matchOverrideUrl(final String url) {
        final boolean[] result = {false};
        Disposable disposable = matching(url).subscribe(new Consumer<MatcherResult>() {
            @Override
            public void accept(MatcherResult matcherResult) throws Exception {
                result[0] = true;
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                result[0] = false;
            }
        });
        mDisposables.add(disposable);
        if (result[0]) {
            mTabItemInteractionListener.openNewWebViewLoadUrl(url);
        }
        return result[0];
    }

    @Override
    public void onLoadFailed() {
        hideLoading();
        isPageLoadFailed = true;
        mPageLoadFailed.setVisibility(View.VISIBLE);
    }

    @Override
    public void onWebViewUrlChanged(String url) {
        mTabItemInteractionListener.onWebViewUrlChanged(url, this);
    }

    @Override
    public boolean onReceivedEnterHttpAuthRequest(XWalkView view, XWalkHttpAuthHandler handler, String host, String realm) {
        return mTabItemInteractionListener.onEnterHttpAuthRequest(view, handler, host, realm);
    }

    @Override
    public void openFileChooser() {
        mTabItemInteractionListener.onOpenFileChooser();
    }

    @Override
    public long getLastSSOTimeStamp() {
        return mTabItemInteractionListener.optLastSSOTime();
    }

    @Override
    public void updateSSOTimeStamp(long timeStamp) {
        mTabItemInteractionListener.updateLastSSOTime(timeStamp);
    }

    @Override
    public void yspOpenDocFile(String data) {
        mTabItemInteractionListener.onOpenDocumentFile(data);
    }

    @Override
    public void nativeEvent(NativeEventModel nativeEventModel) {
        mTabItemInteractionListener.postNativeEvent(nativeEventModel);
    }

    @Override
    public AutoLoginModel getAutoLoginConfig(String url) {
        return mTabItemInteractionListener.getAutoLoginConfig(url);
    }

    @Override
    public boolean shouldLoadUrlSelf(XWalkView view, String url) {
        return mTabItemInteractionListener.shouldWebLoadUrlSelf(view, url);
    }

    @Override
    public String getMenu() {
        return mTabItemInteractionListener.getMenu();
    }

    @Override
    public boolean onShowFileChooser() {
        return mTabItemInteractionListener.onShowFileChooser();
    }

    void loadJsApi(String jsContent) {
        if (mFaceView != null) {
            mFaceView.loadUrl(jsContent);
        }
        if (mWebView != null) {
            mWebView.loadUrl(jsContent);
        }
    }

    void loadWebViewAction(String adapterAction) {
        String data = "javascript:window._yspNativeEventHandler('" + adapterAction + "')";
        if (mFaceView != null) {
            mFaceView.loadUrl(data);
        }
        if (mWebView != null) {
            mWebView.loadUrl(data);
        }
    }

    void loadPCUrl() {
        String url = mJavascriptInterfaceModel == null ? "" : mJavascriptInterfaceModel.getPcUrl();
        if (!TextUtils.isEmpty(url)) {
            Uri uri = Uri.parse(url);
            if (uri != null && !url.contains(ContentValues.YSP_PARAM_FORCE_PC)) {
                Set<String> stringSet = uri.getQueryParameterNames();
                if (stringSet != null && stringSet.size() > 0) {
                    url += "&" + ContentValues.YSP_PARAM_FORCE_PC;
                } else {
                    url += "?" + ContentValues.YSP_PARAM_FORCE_PC;
                }
            }
            mTabItemInteractionListener.openNewWebViewLoadUrl(url);
        }
    }

    void release() {
        mDisposables.clear();
        if (mWebView != null) {
            mWebView.removeJavascriptInterface(ContentValues.JS_OBJECT_CROSSWALK);
            mWebView.stopLoading();
            AndroidSchedulers.mainThread().createWorker().schedule(new Runnable() {
                @Override
                public void run() {
                    mWebView.onDestroy();
                }
            }, 1000, TimeUnit.MILLISECONDS);
        }
        if (mFaceView != null) {
            mFaceView.removeJavascriptInterface(ContentValues.JS_OBJECT_CROSSWALK);
            mFaceView.stopLoading();
            mFaceView.destroy();
        }
        if (mJavascriptInterfaceModel != null) {
            mJavascriptInterfaceModel.destroy();
        }
    }

    void setDefaultFontSize(int defaultFontSize) {
        this.mTextZoom = defaultFontSize;
        if (mWebView != null) {
            mWebView.getSettings().setTextZoom(defaultFontSize);
        }
        if (mFaceView != null) {
            mFaceView.getSettings().setTextZoom(defaultFontSize);
        }
    }

    interface OnTabItemInteractionListener {

        long optLastSSOTime();

        void updateLastSSOTime(long lastSSOTimeStamp);

        void updateProgress(TabItem tabItem, int progress);

        /**
         * TabItem的WebView已经返回到最顶部，需要tabFragment处理返回逻辑
         *
         * @param tabItem 当前WebView的TabItem
         */
        void tabItemBack(TabItem tabItem);

        /**
         * 获取需要注入WebView的JavaScriptInterface对象
         */
        List<XCloudJsModel> getXCloudJsModels();

        void onCloseWindow(TabItem tabItem);

        void onOpenFileChooser();

        /**
         * 当前tabFragment中创建新的WebView加载页面
         *
         * @param url targetURL
         */
        void openNewWebViewLoadUrl(String url);

        /**
         * tabItem的WebView地址栏地址变化
         *
         * @param url     当前地址栏地址
         * @param tabItem 当前tabItem
         */
        void onWebViewUrlChanged(String url, TabItem tabItem);

        void onOpenDocumentFile(String data);

        String getMenu();

        boolean isOpen2WebView();

        /**
         * 当前是否是调试模式，调试模式，适配将决定是否输出日志记录，客户端也需要根据此标示决定是不是保存该日志
         */
        boolean isDebugMode();

        /**
         * WebView访问认证请求,如果自己处理返回true，否则返回false
         */
        boolean onEnterHttpAuthRequest(XWalkView view, XWalkHttpAuthHandler handler, String host, String realm);

        /**
         * 开发者需要设置全局运行时，获取全局运行时的版本
         */
        String getGlobalRTVersion();

        /**
         * 获取cookie，常用于单点登录
         */
        ArrayList<CookieModel> getCookieModels();

        boolean shouldWebLoadUrlSelf(XWalkView view, String url);

        void postNativeEvent(NativeEventModel nativeEventModel);

        boolean onShowFileChooser();

        boolean shouldHandleNoMatcherUrlFromOpenWindow(String url);

        DeveloperAppModel getDeveloperAppModel();

        AutoLoginModel getAutoLoginConfig(String url);

        String getUrlToken(String host);

        ArrayList<RequestHeaderSSOModel> getRequestHeaderSSOModels();

        void yspDownload(TabItem tabItem, String fromUrl, XDownloadModel xDownloadModel);

        boolean showAdapterLoading(String message);

        boolean hideAdapterLoading();
    }
}
